MS-DOS EXE(MZ)形式
COM形式はファイルヘッダを持たないことによる拡張性の欠如や、セグメントレジスタを用いず開始位置も0100Hに固定されていたために8086の機能を活かすことができなかった。そのため、MS-DOSはファイルヘッダを持ったEXEフォーマットを新たに導入した。
再配置可能であり、扱えるメモリ領域も64KBを超えられるという特徴を持つ。
ヘッダを定義する構造体は次のようになっている。(Wineのソースwinnt.hより)
code:fileheader.c
typedef struct _IMAGE_DOS_HEADER {
WORD e_magic; /* 00: MZ Header signature */
WORD e_cblp; /* 02: Bytes on last page of file */
WORD e_cp; /* 04: Pages in file */
WORD e_crlc; /* 06: Relocations */
WORD e_cparhdr; /* 08: Size of header in paragraphs */
WORD e_minalloc; /* 0a: Minimum extra paragraphs needed */
WORD e_maxalloc; /* 0c: Maximum extra paragraphs needed */
WORD e_ss; /* 0e: Initial (relative) SS value */
WORD e_sp; /* 10: Initial SP value */
WORD e_csum; /* 12: Checksum */
WORD e_ip; /* 14: Initial IP value */
WORD e_cs; /* 16: Initial (relative) CS value */
WORD e_lfarlc; /* 18: File address of relocation table */
WORD e_ovno; /* 1a: Overlay number */
WORD e_res4; /* 1c: Reserved words */ WORD e_oemid; /* 24: OEM identifier (for e_oeminfo) */
WORD e_oeminfo; /* 26: OEM information; e_oemid specific */
WORD e_res210; /* 28: Reserved words */ DWORD e_lfanew; /* 3c: Offset to extended header */
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
COM形式との区別のため、ファイルの先頭2バイトがマジックナンバー'MZ'(または'ZM')になっている。これはMS-DOS 2.0の開発責任者の一人Mark Zbikowskiのイニシャルに由来するらしい。
日本語コメント付きヘッダ定義(システムソフトウェア構成論レジュメより)
https://gyazo.com/44c20b7ac6a053e7c24adb5e664460f2
ロード手順
メモリ領域を確保
領域の大きさはPSP+loadサイズ+maxalloc+spサイズ
メモリ不足のときはmaxallocをminallocまで減らしていく
ロード nblocks*512 + lastsize
再配置処理(ロード時なので静的再配置である)
セグメントレジスタをセット
ヘッダのipポインタの位置にfar jump(cs:ipの位置)
再配置処理
コード内のアドレス値はロード時に変換しなければならないが、アドレス値はセグメント値+オフセット値で表しているためセグメント値を変化させる(ロード前は基本0開始前提なので主にcsの値を足す)だけで良い
code:hello.asm
1 ;------------------------------------
2 ; サンプルプログラム HELLO.ASM
3 ; 「Hello !」と表示します
4 ;------------------------------------
5 ASSUME CS:CSEG, DS:DSEG, SS:SSEG
6 CSEG SEGMENT WORD
7 START: MOV AX, DSEG
8 MOV DS, AX
9 MOV DX, OFFSET MSG ; DS:DX で MSG を指す
10 MOV AH, 9h
11 INT 21h ; 文字列 MSG を表示
12 MOV AX, 4C00h
13 INT 21h ; プログラムを終了
14 CSEG ENDS
15
16 DSEG SEGMENT WORD
17 MSG DB 'Hello !', 0Dh, 0Ah, '$'
18 DSEG ENDS
19
20 SSEG SEGMENT STACK
21 DB 100h DUP(?)
22 SSEG ENDS
23
24 END START ; 実行開始アドレスは START
0Dhは復行、0Ahは改行、$は表示データの終わりを意味する。
INT 21hはInterruput命令でソフトウェア割り込みを表す。MS-DOSでは各レジスタに必要な値をセットしてINT 21hを実行することでシステムコールを発行できることになっている。